package org.budo.support.lang.util;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author lmw
 */
public class ArrayUtil {
    public static String[] toStringArray(Object[] array) {
        if (null == array) {
            return null;
        }

        String[] stringArray = new String[array.length];
        for (int i = 0; i < array.length; i++) {
            Object each = array[i];
            stringArray[i] = null == each ? null : each.toString();
        }

        return stringArray;
    }

    public static Object[] toObjectArray(char[] charArray) {
        if (null == charArray) {
            return null;
        }

        Object[] objectArray = new Object[charArray.length];
        for (int i = 0; i < charArray.length; i++) {
            objectArray[i] = charArray[i];
        }

        return objectArray;
    }

    public static <T> T[] toArray(Collection<T> collection) {
        Class<?> collectionType = collection.getClass();
        Class<?> componentType = collectionType.getComponentType();
        int collectionSize = collection.size();
        T[] array = (T[]) Array.newInstance(componentType, collectionSize);
        return collection.toArray(array);
    }

    public static <T> T[] toArray(T... items) {
        return items;
    }

    public static Integer[] sequence(Integer from, Integer to, Integer step) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = from; i <= to; i = i + step) {
            list.add(new Integer(i));
        }
        return list.toArray(new Integer[0]);
    }

    public static Integer[] sequence(Integer from, Integer to) {
        return sequence(from, to, 1);
    }

    public static int[] sequence_2(int from, int to) {
        return sequence_2(from, to, 1);
    }

    public static int[] sequence_2(Integer from, Integer to, Integer step) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = from; i <= to; i = i + step) {
            list.add(new Integer(i));
        }

        int[] ints = (int[]) Array.newInstance(int.class, list.size());

        for (int i = 0; i < ints.length; i++) {
            ints[i] = list.get(i);
        }
        return ints;
    }

    /**
     * 合并多个数组
     * 
     * @param array_1    第一个数组
     * @param array_2    第二个数组
     * @param moreArrays 更多数组
     * @return 合并后的新的数组
     */
    public static <T> T[] concat(T[] array_1, T[] array_2, T[]... moreArrays) {
        if (null == array_1 && null == array_2) {
            throw new IllegalArgumentException("array_1 and array_2 can not be null, array_1=" + array_1 + ", array_2=" + array_2);
        }

        List<T> listAll = new ArrayList<T>();
        if (null != array_1) {
            List<T> list_1 = Arrays.asList(array_1);
            listAll.addAll(list_1);
        }

        if (null != array_2) {
            List<T> list_2 = Arrays.asList(array_2);
            listAll.addAll(list_2);
        }

        if (null != moreArrays) {
            for (T[] each : moreArrays) {
                List<T> listEach = Arrays.asList(each);
                listAll.addAll(listEach);
            }
        }

        T[] resultArray = null != array_1 ? array_1 : array_2;
        return listAll.toArray(resultArray);
    }

    public static byte[] subArray(byte[] input, int from, int length) {
        try {
            if (length + from > input.length) {
                length = input.length - from;
            }
            byte[] dest = new byte[length];
            System.arraycopy(input, from, dest, 0, length);
            return dest;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T[] subArray(T[] input, int from) {
        try {
            Class<?> arrayType = input.getClass();
            Class<?> componentType = arrayType.getComponentType();

            int len = input.length - from;

            T[] dest = (T[]) Array.newInstance(componentType, len);
            System.arraycopy(input, from, dest, 0, len);

            return dest;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String[] subArray(String[] input, int from) {
        try {
            int len = input.length - from;
            String[] dest = new String[len];
            System.arraycopy(input, from, dest, 0, len);
            return dest;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> Boolean isEmpty(T[] array) {
        return null == array || array.length == 0;
    }

    /**
     * 追加若干项到数组结尾
     */
    public static <T> T[] append(T[] array1, T... array2) {
        int newLength = array1.length + array2.length;
        T[] result = Arrays.copyOf(array1, newLength);
        System.arraycopy(array2, 0, result, array1.length, array2.length);
        return result;
    }

    public static byte[] append(byte[] array1, byte... array2) {
        byte[] result = Arrays.copyOf(array1, array1.length + array2.length);
        System.arraycopy(array2, 0, result, array1.length, array2.length);
        return result;
    }

    public static String toString(Object... array) {
        StringBuffer stringBuffer = new StringBuffer();
        if (null != array && array.length > 0) {
            for (int i = 0; i < array.length - 1; i++) {
                stringBuffer.append(array[i]).append(',');
            }
            Object each = array[array.length - 1];
            if (each instanceof Map) {
                stringBuffer.append(MapUtil.toString((Map) each));
            } else if (each instanceof Collection) {
                stringBuffer.append(toString(((Collection) each).toArray()));
            } else {
                stringBuffer.append(each);
            }
        }
        return stringBuffer.toString();
    }

    public static <T> T[] remove(T[] array, T... toRemove) {
        List<T> result = new ArrayList<T>();
        for (T each : array) {
            if (!contains(toRemove, each)) {
                result.add(each);
            }
        }
        return (T[]) result.toArray(); // 这里不应传入 array，因为长度变了
    }

    public static Boolean contains(Object[] array, Object one) {
        for (Object each : array) {
            if ((null == each && null == one) //
                    || (null != each && null != one && each.equals(one))) {
                return true;
            }
        }
        return false;
    }

    public static <T> Integer length(T[] array) {
        return null == array ? null : array.length;
    }

    public static <T> T first(T[] array) {
        return (null == array || array.length < 1) ? null : array[0];
    }

    public static <T> T last(T[] array) {
        return (null == array || array.length < 1) ? null : array[array.length - 1];
    }

    public static <T> T[] sort(T... array) {
        Arrays.sort(array);
        return array;
    }

    public static List<Byte> toByteList(byte[] bytes) {
        if (null == bytes) {
            return null;
        }

        int len = bytes.length;
        List<Byte> list = new ArrayList<Byte>(len);

        if (len < 1) {
            return list;
        }

        for (int i = 0; i < len; i++) {
            list.add(bytes[i]);
        }
        return list;
    }
}